package com.reebake.ideal.storage.controller.client;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.reebake.ideal.storage.client.FileUploadClient;
import com.reebake.ideal.storage.entity.FileInfoDTO;
import com.reebake.ideal.storage.entity.FileUploadRequestDTO;
import com.reebake.ideal.storage.properties.StorageProperties;
import com.reebake.ideal.storage.util.StorageUtil;
import com.reebake.ideal.storage.vo.Base64DecodedMultipartFile;
import jakarta.servlet.http.HttpServletRequest;
import lombok.SneakyThrows;
import net.coobird.thumbnailator.filters.Watermark;
import net.coobird.thumbnailator.geometry.Position;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.dromara.x.file.storage.core.file.HttpServletRequestFileWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/client/storage/file")
public class FileUploadClientController implements FileUploadClient {
    @Autowired
    private StorageProperties storageProperties;
    @Autowired
    private FileStorageService fileStorageService;//注入实列

    @Override
    public FileInfoDTO upload(@RequestParam(required = false) String platform, @RequestParam(required = false) String path, @RequestParam(required = false) String originalFilename, MultipartFile file) {
        FileInfo fileInfo = fileStorageService.of(file)
                .setPlatform(StrUtil.isNotBlank(platform), platform)
                .setPath(StrUtil.isNotBlank(path), path)
                .setOriginalFilename(StrUtil.isNotBlank(originalFilename), originalFilename)
                .upload();
        return StorageUtil.toFileInfoDTO(fileInfo);
    }

    @Override
    public FileInfoDTO uploadImage(@RequestParam(required = false) String platform, @RequestParam(required = false) String path, @RequestParam(required = false) String originalFilename
            , @RequestParam(required = false) String waterMarkText, @RequestParam(required = false) Boolean useThumbnail
            , MultipartFile file) {
        Integer imgWidth = storageProperties.getImageWidth();
        Integer imgHeight = storageProperties.getImageHeight();
        Integer thWidth = storageProperties.getThumbnailImageWidth();
        Integer thHeight = storageProperties.getThumbnailImageHeight();
        FileInfo fileInfo = fileStorageService.of(file)
                .setPlatform(StrUtil.isNotBlank(platform), platform)
                .setPath(StrUtil.isNotBlank(path), path)
                .setOriginalFilename(StrUtil.isNotBlank(originalFilename), originalFilename)
                .image(img -> {
                    if(StrUtil.isNotBlank(waterMarkText)) {
                        for(Watermark watermark : createWaterMark(imgWidth, imgHeight, waterMarkText)) {
                            img.watermark(watermark);
                        }
                    }
                    img.size(imgWidth, imgHeight);
                })
                .thumbnail(BooleanUtil.isTrue(useThumbnail), th -> th.size(thWidth, thHeight))  //再生成一张缩略图
                .upload();
        return StorageUtil.toFileInfoDTO(fileInfo);
    }

    @Override
    public FileInfoDTO upload(@RequestBody FileUploadRequestDTO file) {
        Base64DecodedMultipartFile multipartFile = (Base64DecodedMultipartFile) Base64DecodedMultipartFile.base64ToMultipart(file.getFile());
        String platform = file.getPlatform();
        String path = file.getPath();
        String originalFilename = file.getOriginalFilename();
        FileInfo fileInfo = fileStorageService.of(multipartFile)
                .setPlatform(StrUtil.isNotBlank(platform), platform)
                .setPath(StrUtil.isNotBlank(path), path)
                .setOriginalFilename(StrUtil.isNotBlank(originalFilename), originalFilename)
                .upload();
        return StorageUtil.toFileInfoDTO(fileInfo);
    }

    @SneakyThrows
    private List<Watermark> createWaterMark(Integer width, Integer height, String waterMarkText) {
        String imageUrl = storageProperties.getWaterMarkImageUrl();
        String text = waterMarkText;
        Integer waterMarkImageWidth = storageProperties.getWaterMarkImageWidth();
        Integer waterMarkImageHeight = storageProperties.getWaterMarkImageHeight();
        Float waterMarkOpacity = storageProperties.getWaterMarkOpacity();

        BufferedImage bufferedImage = null;
        if(StrUtil.isNotBlank(imageUrl)) {
            byte[] bytes = fileStorageService.download(imageUrl).bytes();
            bufferedImage = ImageIO.read(new ByteArrayInputStream(bytes));
            waterMarkImageWidth = bufferedImage.getWidth();
            waterMarkImageHeight = bufferedImage.getHeight();
        }else {
            bufferedImage = StorageUtil.createTextWaterMark(text, waterMarkImageWidth, waterMarkImageHeight);
        }
        List<Watermark> watermarks = new ArrayList<>();
        for(Integer w = 0; w <= width; w += waterMarkImageWidth) {
            final Integer x =w;
            for(Integer h = 0; h <= height; h += waterMarkImageHeight) {
                final Integer y = h;
                Position position = new Position() {
                    @Override
                    public Point calculate(int enclosingWidth, int enclosingHeight, int width, int height, int insetLeft, int insetRight, int insetTop, int insetBottom) {
                        return new Point(x, y);
                    }
                };
                Watermark watermark = new Watermark(position, bufferedImage, waterMarkOpacity);
                watermarks.add(watermark);
            }
        }
        return watermarks;

    }

    /**
     * 直接读取 HttpServletRequest 中的文件进行上传，成功返回文件信息
     * 这种方式通过直接读取输入流进行上传，可以实现文件不落盘，边读取边上传，速度更快
     * 使用这种方式有些注意事项，请查看文档 基础功能-上传 章节
     */
    @PostMapping("/upload-request")
    public FileInfo uploadRequest(HttpServletRequest request) {
        HttpServletRequestFileWrapper wrapper = (HttpServletRequestFileWrapper) fileStorageService.wrapper(request);

        //获取指定参数，注意无法获取文件类型的参数
        String platform = wrapper.getParameter("platform");
        String path = wrapper.getParameter("path");
        String originalFilename = wrapper.getParameter("originalFilename");

        return fileStorageService.of(wrapper)
                .setPlatform(StrUtil.isNotBlank(platform), platform)
                .setPath(StrUtil.isNotBlank(path), path)
                .setOriginalFilename(StrUtil.isNotBlank(originalFilename), originalFilename)
                .upload();
    }
}

